﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../global/head.h"
#include "../xos/head.h"
#include "file_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static file_impl::POOL * pool_ptr = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    file_impl::file_impl()
    {
        memset( m_szFileName, 0, sizeof( m_szFileName ) );
        m_enumType = FILE_TYPE_NONE;
        m_hFile = -1;
    }

    file_impl::~file_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int file_impl::get_addr( POOL *** pppPool, LIST *** pppList )
    {
        int ret = 0;
        if( pppPool )
        {
            *pppPool = &pool_ptr;
        }
        if( pppList )
        {
            *pppList = 0;
        }
        return ret;
    }

    int file_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int file_impl::term()
    {
        int nRet = 0;

        close();

        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////
    // 
    // open a file
    // 
    int file_impl::open( const char * lpszFileName, unsigned long ulAccessFlag, unsigned long ulShareMode, unsigned long ulCreateFlag )
    {
        int nRet = 0;

        unsigned long ulFileFlag = 0;

        // access type

        if( FILE_READ & ulAccessFlag )
        {
            ulFileFlag |= O_RDONLY;
        }

        if( FILE_WRITE & ulAccessFlag )
        {
            ulFileFlag |= O_WRONLY | O_RDONLY;
        }

        // create type

        if( ulCreateFlag & FILE_CREATE )
        {
            ulFileFlag |= O_CREAT;
        }

        // 
        // share type
        // 
        if( ulCreateFlag & FILE_OPEN )
        {
            ulFileFlag |= 0;
        }

        if( 0 == nRet )
        {
            m_hFile = ::open( lpszFileName, ulFileFlag, 0666 );

            if( -1 == m_hFile )
            {
                nRet = 1;
            }
        }

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    // 
    // get file time
    // 
    int file_impl::get_file_time( xos::xos_i64 * lpCreateTime, xos::xos_i64 * lpAccessTime, xos::xos_i64 * lpModifyTime )
    {
        int nRet = 0;

        struct stat st = { 0 };

        if( 0 == nRet )
        {
            nRet = fstat( m_hFile, &st );
        }

        if( ( 0 == nRet ) && lpCreateTime )
        {
            *lpCreateTime = st.st_ctime;
        }

        if( ( 0 == nRet ) && lpAccessTime )
        {
            *lpAccessTime = st.st_atime;
        }

        if( ( 0 == nRet ) && lpModifyTime )
        {
            *lpModifyTime = st.st_mtime;
        }

        return nRet;
    }

    // 
    // get file or dir name
    // 
    const char * file_impl::get_file_name( char * lpszFileName, int nLen, int * pnLenNeeded )
    {
        if( pnLenNeeded )
        {
            *pnLenNeeded = strlen( m_szFileName );
        }

        if( lpszFileName )
        {
            strcpy( lpszFileName, m_szFileName );
        }

        return m_szFileName;
    }

    // 
    // is file or dir ? 
    // 
    i_file::enumFileType file_impl::get_file_type()
    {
        return m_enumType;
    }

    // 
    // move file pointer to ...
    // 
    int file_impl::set_file_pos( enumFilePos enumFrom, xos_i64 iPos64, xos_i64 * lpSeek64 )
    {
        int nRet = 0;

        off_t tOffset = iPos64, tSeekRet = -1;
        unsigned long ulType = 0;

        if( 0 == nRet )
        {
            switch( enumFrom )
            {
            case FILE_POS_BEGIN:
                {
                    ulType = SEEK_SET;
                }
                break;
            case FILE_POS_CUR:
                {
                    ulType = SEEK_CUR;
                }
                break;
            case FILE_POS_END:
                {
                    ulType = SEEK_END;
                }
                break;
            default:
                {
                    nRet = 1;
                }
                break;
            }
        }

        if( 0 == nRet )
        {
            if( -1 == m_hFile )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            tSeekRet = lseek( m_hFile, tOffset, ulType );
        }

        if( lpSeek64 )
        {
            *lpSeek64 = tSeekRet;
        }

        return nRet;
    }

    // 
    // get current file pointer
    // 
    int file_impl::get_file_pos( xos_i64 * lpSize64 )
    {
        int nRet = 0;

        off_t tOffset = 0;

        if( -1 == m_hFile )
        {
            nRet = 1;
        }

        if( 0 == nRet )
        {
            tOffset = lseek( m_hFile, 0, SEEK_CUR );
        }

        if( 0 == nRet )
        {
            *lpSize64 = tOffset;
        }

        return nRet;
    }

    // 
    // get current file pointer
    // 
    int file_impl::get_file_size( xos_i64 * lpSize64 )
    {
        int nRet = 0;

        struct stat st = { 0 };
        off_t st_size = 0;

        if( -1 == m_hFile )
        {
            nRet = 1;
        }

        if( 0 == nRet )
        {
            fstat( m_hFile, &st );
            st_size = st.st_size;
        }

        if( 0 == nRet )
        {
            *lpSize64 = st_size;
        }

        return nRet;
    }

    // 
    // commit file disk space.
    // 
    int file_impl::commit_file( xos_i64 iPos64 )
    {
        int nRet = 0;

        off_t st_size = iPos64, st_pos = 0;
        char buf[4096] = { 0 };
        int ret = 0;

        lseek( m_hFile, 0, SEEK_SET );

        while( ( -1 != ret ) && ( st_pos < st_size ) )
        {
            off_t len = sizeof( buf );

            if( st_size < st_pos + len )
            {
                len = st_size - st_pos;
            }

            st_pos += len;

            ret = ::write( m_hFile, buf, len );
        }

        lseek( m_hFile, 0, SEEK_SET );

        return nRet;
    }

    // 
    // read file data
    // 
    // -1 means failed. other , read bytes
    //
    int file_impl::read( void * lpMsg, unsigned long ulBufSize )
    {
        int nRet = 0;

        if( -1 == m_hFile )
        {
            nRet = -1;
        }

        if( 0 == nRet )
        {
            nRet = ::read( m_hFile, lpMsg, ulBufSize );
        }

        return nRet;
    }

    // 
    // write file data
    // 
    // -1 means failed. other , write bytes
    // 
    int file_impl::write( const void * lpMsg, unsigned long ulBufSize )
    {
        int nRet = 0;

        if( -1 == m_hFile )
        {
            nRet = -1;
        }

        if( 0 == nRet )
        {
            nRet = ::write( m_hFile, lpMsg, ulBufSize );
        }

        return nRet;
    }

    // 
    // close file handle
    //  
    int file_impl::close()
    {
        int nRet = 0;

        memset( m_szFileName, 0, sizeof( m_szFileName ) );
        m_enumType = FILE_TYPE_NONE;

        if( -1 != m_hFile )
        {
            ::close( m_hFile );
            m_hFile = -1;
        }

        return nRet;
    }
} // xos
